package com.gkzf.ai.module.crm.service.creditReport;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.gkzf.ai.framework.common.util.object.BeanUtils;
import com.gkzf.ai.module.crm.config.BaseService;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.admittancecondition.CreditReportAdmittanceConditionSaveReqVO;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.admittancecondition.OverdueRecordVo;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.admittancecondition.QueryLimitVo;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.creditCardDetails.CreditReportCreditCardDetailsRespVO;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.creditLoanDetails.CreditReportLoanDetailsRespVO;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.creditreportbasic.CreditReportBasicRespVO;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.creditreportbasic.CreditReportBasicSaveReqVO;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.creditreportdetails.CreditReportDetailsRespVO;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.creditreportdetails.CreditReportDetailsSaveReqVO;
import com.gkzf.ai.module.crm.dal.dataobject.creditReport.*;
import com.gkzf.ai.module.crm.dal.mysql.creditReport.CreditReportDetailsMapper;
import com.gkzf.ai.module.crm.util.YearlyRecord;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Predicate;

import static com.gkzf.ai.framework.common.util.date.UniversalDateTimeConverter.convert;
import static com.gkzf.ai.module.crm.util.AnalysisJsonObjectUtils.*;
import static com.gkzf.ai.module.crm.util.assembly.AssemblyCreditReportDetails.getOverdueRecordVos;
import static com.gkzf.ai.module.crm.util.assembly.AssemblyCreditReportDetails.processOverdueField;


/**
 * CRM 征信报告详情 Service 实现类
 *
 * @author 国科智飞
 */
@Service
@Validated
@Slf4j
public class CreditReportDetailsServiceImpl extends BaseService<CreditReportDetailsDO> implements CreditReportDetailsService {

    @Resource
    private CreditReportLoanOverdueService creditReportLoanOverdueService;

    @Resource
    private CreditReportLoanDetailsService creditReportLoanDetailsService;

    @Resource
    private CreditReportCreditCardDetailsService creditReportCreditCardDetailsService;

    @Resource
    private CreditReportDetailsMapper creditReportDetailsMapper;
    @Resource
    private CreditReportBasicService creditReportBasicService;
    @Resource
    private CreditReportAdmittanceConditionService creditReportAdmittanceConditionService;
    @Override
    public Long createCreditReportDetails(CreditReportDetailsSaveReqVO createReqVO) {
        // 插入
        CreditReportDetailsDO creditReportDetails = BeanUtils.toBean(createReqVO, CreditReportDetailsDO.class);
        LambdaUpdateWrapper<CreditReportDetailsDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(CreditReportDetailsDO::getCreditBasicId, creditReportDetails.getCreditBasicId());
        List<CreditReportDetailsDO> detailsDOS = creditReportDetailsMapper.selectList(updateWrapper);
        if (detailsDOS.isEmpty()) {
            creditReportDetailsMapper.insert(creditReportDetails);
            return creditReportDetails.getId();
        }else {
            creditReportDetailsMapper.update(creditReportDetails,updateWrapper);
            return detailsDOS.get(0).getId();
        }

        // 返回

    }


    public static boolean isToday(String input) {
          final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        try {
            // 解析输入为 LocalDateTime
            LocalDateTime inputDateTime = LocalDateTime.parse(input, formatter);

            // 提取日期部分并与今天比较
            LocalDate inputDate = inputDateTime.toLocalDate();
            LocalDate today = LocalDate.now();

            return inputDate.isEqual(today);
        } catch (DateTimeParseException e) {
            log.info("非法日期格式: {}", e.getMessage());
            return false;
        }
    }

    @Override
    @Transactional
    public void updateCreditReportDetails(CreditReportDetailsSaveReqVO updateReqVO) {
        CreditReportDetailsDO creditReportDetailsDO = creditReportDetailsMapper.selectById(updateReqVO.getId());
        if (Objects.isNull(creditReportDetailsDO)) {
            creditReportDetailsMapper.insert(BeanUtils.toBean(updateReqVO, CreditReportDetailsDO.class));
        }
        LambdaQueryWrapper<CreditReportDetailsDO> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(CreditReportDetailsDO::getCreditBasicId, creditReportDetailsDO.getCreditBasicId());
        List<CreditReportDetailsDO> creditReportDetailsDOS = creditReportDetailsMapper.selectList(queryWrapper);
        CreditReportBasicSaveReqVO basicRespVO = updateReqVO.getBasicReqVO();
        // 重新计算余额
        getTotalLiabilities(updateReqVO);
        String idNumber = basicRespVO.getIdNumber();
        extracted(updateReqVO);
        Map<String,List<OverdueRecordVo>> overdueSummaryMap = calculateOverdue(updateReqVO);
        updateReqVO.setCreditReportOverdueJson(JSON.toJSONString(overdueSummaryMap));
        creditReportBasicService.updateCreditReportBasic(basicRespVO);
        String creditAnalysis = creditReportAdmittanceConditionService.assemblingPersonalCreditReportDetails(updateReqVO);
        log.info("征信解析的字段:{}",creditAnalysis);
        creditReportDetailsDOS.forEach(creditReportDetails -> {
            // 校验存在
            creditReportLoanOverdueService.updateCreditReportLoanOverdue(updateReqVO.getLoanOverdueList());
            creditReportLoanDetailsService.updateCreditReportLoanDetails(updateReqVO.getLoanOverdueDetailsList());
            creditReportCreditCardDetailsService.updateCreditReportCreditCardDetails(updateReqVO.getLoanOverdueCreditCardDetailsList());
            // 更新
            CreditReportDetailsDO updateObj = BeanUtils.toBean(updateReqVO, CreditReportDetailsDO.class);
            updateObj.setId(creditReportDetails.getId());
            creditReportDetailsMapper.updateById(updateObj);
        });
        // 同步修改用户征信报告表
        creditReportAdmittanceConditionService.updateCreditReportAdmittanceCondition(updateReqVO, idNumber,basicRespVO);
    }

    /**
     * 根据传入的CreditReportDetailsSaveReqVO对象，计算信用卡当前使用率和信用卡月平均使用率
     */
    public void extracted(CreditReportDetailsSaveReqVO updateReqVO) {
        // 如果信用卡已使用额度大于0，且信用卡最大额度大于0，则计算信用卡当前使用率
        if (updateReqVO.getCreditCardUsedCredit().compareTo(BigDecimal.ZERO) > 0 &&  updateReqVO.getCreditCardMaxMoney().compareTo(BigDecimal.ZERO) > 0){
            // 计算信用卡当前使用率，保留四位小数，四舍五入
            updateReqVO.setCreditCardCurrentRate(updateReqVO.getCreditCardUsedCredit().
                    divide(updateReqVO.getCreditCardMaxMoney(),4, RoundingMode.HALF_UP).multiply(new BigDecimal(100)));
        }else {
            // 否则，将信用卡当前使用率设为0
            updateReqVO.setCreditCardCurrentRate(BigDecimal.ZERO);
        }
        // 如果信用卡月平均使用额度大于0，且信用卡最大额度大于0，则计算信用卡月平均使用率
        if (updateReqVO.getCreditCardMonthAverage().compareTo(BigDecimal.ZERO) > 0
                && updateReqVO.getCreditCardMaxMoney().compareTo(BigDecimal.ZERO) > 0){
            // 计算信用卡月平均使用率，保留四位小数，四舍五入
            updateReqVO.setCreditCardMonthRete(updateReqVO.getCreditCardMonthAverage()
                    .divide(updateReqVO.getCreditCardMaxMoney(),4,RoundingMode.HALF_UP)
                    .multiply(new BigDecimal(100)));
        }else {
            // 否则，将信用卡月平均使用率设为0
            updateReqVO.setCreditCardMonthRete(BigDecimal.ZERO);
        }
    }

    @Override
    public void deleteCreditReportDetails(Long id) {
        // 删除
        creditReportDetailsMapper.deleteById(id);
    }


    @Override
    public CreditReportDetailsRespVO getCreditReportDetails(Long creditBasicId) {
        LambdaQueryWrapper<CreditReportDetailsDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CreditReportDetailsDO::getCreditBasicId, creditBasicId);
        CreditReportDetailsDO creditReportDetailsDO = creditReportDetailsMapper.selectOne(queryWrapper);
        CreditReportDetailsRespVO bean = BeanUtils.toBean(creditReportDetailsDO, CreditReportDetailsRespVO.class);
        // 基本信息
        CreditReportBasicRespVO basicRespVO = BeanUtils.toBean(creditReportBasicService.getCreditReportBasic(bean.getCreditBasicId()), CreditReportBasicRespVO.class);
        // 逾期明细
        List<CreditReportLoanOverdueDO> creditReportLoanOverdue = creditReportLoanOverdueService.getCreditReportLoanOverdueByDetailsId(creditReportDetailsDO.getId());
        //贷款明细
        List<CreditReportLoanDetailsDO> creditReportLoanOverdueDOList = creditReportLoanDetailsService.getCreditReportLoanDetailsList(creditReportDetailsDO.getId());
        List<CreditReportLoanDetailsRespVO> loanOverdueRespList = BeanUtils.toBean(creditReportLoanOverdueDOList, CreditReportLoanDetailsRespVO.class);
        //信用卡明细
        List<CreditReportCreditCardDetailsDO> creditReportCreditCardDetailsList = creditReportCreditCardDetailsService.getCreditReportCreditCardDetailsList(creditReportDetailsDO.getId());
        List<CreditReportCreditCardDetailsRespVO> creditCardRespList = BeanUtils.toBean(creditReportCreditCardDetailsList, CreditReportCreditCardDetailsRespVO.class);
        bean.setLoanOverdueList(creditReportLoanOverdue);
        bean.setLoanOverdueDetailsList(loanOverdueRespList);
        bean.setLoanOverdueCreditCardDetailsList(creditCardRespList);
        bean.setBasicRespVO(basicRespVO);
        if (Objects.nonNull(creditReportDetailsDO.getReportTime())){
            bean.setIsToday(isToday(convert(creditReportDetailsDO.getReportTime())));
        }
        return bean;
    }



    /**
     * 用户信用评分计算
     *  统计信用评分 {<a href="https://aiguoke.yuque.com/hkt27g/qpn99h/hynkrgz1w7srhrib">...</a>} 文档
     * @param detailsDO 征信报告详情
     */
    public int statisticsCreditScore(CreditReportDetailsSaveReqVO detailsDO, CreditReportAdmittanceConditionSaveReqVO conditionDO){
        // 征信报告总分600，减分机制
        /*
            非银行机构数
         */
        Map<Predicate<CreditReportDetailsSaveReqVO>,Integer> predicateMap = new LinkedHashMap<>();
        // 非银行机构数 3-5 -10
        predicateMap.put(item ->Objects.nonNull(item.getNonBankingOrganizationAccount()) && detailsDO.getNonBankingOrganizationAccount() > 3 && detailsDO.getNonBankingOrganizationAccount() <= 5, -10);
        // 非银行机构数 6-7 -20
        predicateMap.put(item ->Objects.nonNull(item.getNonBankingOrganizationAccount()) && detailsDO.getNonBankingOrganizationAccount() > 5 && detailsDO.getNonBankingOrganizationAccount() <= 7, -20);
        // 非银行机构数 > 7 -30
        predicateMap.put(item ->Objects.nonNull(item.getNonBankingOrganizationAccount()) && detailsDO.getNonBankingOrganizationAccount() > 7, -30);
        /*
            信用卡当前使用率
         */
        // 60 < 当前使用率 <= 70 	-10
        predicateMap.put(item ->Objects.nonNull(detailsDO.getCreditCardCurrentRate()) && isGreater(detailsDO.getCreditCardCurrentRate(), BigDecimal.valueOf(60))
                && isLessOrEqual(detailsDO.getCreditCardCurrentRate(), BigDecimal.valueOf(70)),-10);
        // 70 < 当前使用率 <= 80 	-20
        predicateMap.put(item ->Objects.nonNull(detailsDO.getCreditCardCurrentRate()) && isGreater(detailsDO.getCreditCardCurrentRate(), BigDecimal.valueOf(70))
                && isLessOrEqual(detailsDO.getCreditCardCurrentRate(), BigDecimal.valueOf(80)),-20);
        // 80 < 当前使用率 <= 90 	-30
        predicateMap.put(item ->Objects.nonNull(detailsDO.getCreditCardCurrentRate()) && isGreater(detailsDO.getCreditCardCurrentRate(), BigDecimal.valueOf(80))
                && isLessOrEqual(detailsDO.getCreditCardCurrentRate(), BigDecimal.valueOf(90)),-30);
        // 当前使用率 > 90 	-40
        predicateMap.put(item ->Objects.nonNull(detailsDO.getCreditCardCurrentRate()) && isGreater(detailsDO.getCreditCardCurrentRate(), BigDecimal.valueOf(90)),-40);
        /*
            平均6个月使用率
         */
        // 60 < 平均6个月使用率 <= 70 	-10
        predicateMap.put(item ->Objects.nonNull(detailsDO.getCreditCardMonthRete()) && isGreater(detailsDO.getCreditCardMonthRete(), BigDecimal.valueOf(60))
                && isLessOrEqual(detailsDO.getCreditCardCurrentRate(), BigDecimal.valueOf(70)),-10);
        // 70 < 平均6个月使用率 <= 80 	-20
        predicateMap.put(item ->Objects.nonNull(detailsDO.getCreditCardMonthRete()) && isGreater(detailsDO.getCreditCardMonthRete(), BigDecimal.valueOf(70))
                && isLessOrEqual(detailsDO.getCreditCardCurrentRate(), BigDecimal.valueOf(80)),-20);
        // 80 < 平均6个月使用率 <= 90 	-30
        predicateMap.put(item ->Objects.nonNull(detailsDO.getCreditCardMonthRete()) && isGreater(detailsDO.getCreditCardMonthRete(), BigDecimal.valueOf(80))
                && isLessOrEqual(detailsDO.getCreditCardCurrentRate(), BigDecimal.valueOf(90)),-30);
        // 平均6个月使用率 > 90 	-40
        predicateMap.put(item ->Objects.nonNull(detailsDO.getCreditCardMonthRete()) && isGreater(detailsDO.getCreditCardMonthRete(), BigDecimal.valueOf(90)),-40);
        /*
            负债总额
         */
        // 10 < 负债总额 <= 30 	-10
        predicateMap.put(item ->Objects.nonNull(detailsDO.getTotalLiabilities()) && isGreater(detailsDO.getTotalLiabilities(), BigDecimal.valueOf(100000))
                && isLessOrEqual(detailsDO.getTotalLiabilities(), BigDecimal.valueOf(300000)),-10);
        // 30 < 负债总额 <= 50 	-20
        predicateMap.put(item ->Objects.nonNull(detailsDO.getTotalLiabilities()) && isGreater(detailsDO.getTotalLiabilities(), BigDecimal.valueOf(300000))
                && isLessOrEqual(detailsDO.getTotalLiabilities(), BigDecimal.valueOf(500000)),-20);
        // 50 < 负债总额 <= 80 	-30
        predicateMap.put(item ->Objects.nonNull(detailsDO.getTotalLiabilities()) && isGreater(detailsDO.getTotalLiabilities(), BigDecimal.valueOf(500000))
                && isLessOrEqual(detailsDO.getTotalLiabilities(), BigDecimal.valueOf(800000)),-30);
        // 80 < 负债总额 <= 100 	-40
        predicateMap.put(item ->Objects.nonNull(detailsDO.getTotalLiabilities()) && isGreater(detailsDO.getTotalLiabilities(), BigDecimal.valueOf(800000))
                && isLessOrEqual(detailsDO.getTotalLiabilities(), BigDecimal.valueOf(1000000)),-40);
        // 100 < 负债总额 <= 150 	-50
        predicateMap.put(item ->Objects.nonNull(detailsDO.getTotalLiabilities()) && isGreater(detailsDO.getTotalLiabilities(), BigDecimal.valueOf(1000000))
                && isLessOrEqual(detailsDO.getTotalLiabilities(), BigDecimal.valueOf(1500000)),-50);
        // 150 < 负债总额 <= 200 	-60
        predicateMap.put(item ->Objects.nonNull(detailsDO.getTotalLiabilities()) && isGreater(detailsDO.getTotalLiabilities(), BigDecimal.valueOf(1500000))
                && isLessOrEqual(detailsDO.getTotalLiabilities(), BigDecimal.valueOf(2000000)),-60);
        // 负债总额 > 200 	-70
        predicateMap.put(item ->Objects.nonNull(detailsDO.getTotalLiabilities()) && isGreater(detailsDO.getTotalLiabilities(), BigDecimal.valueOf(2000000)),-70);
        /*
            查询次数
            机构查询一个月内>3次	-20
            机构查询两个月内>5次	-20
            机构查询三个月内>7次	-20
            机构查询六个月内>9次	-20
            机构查询一年内>15	    -20
            机构查询两年内>30	    -20
         */
        analysisQueryRecord(detailsDO.getCreditReportQueryJson(), queryLimitVoList -> {
            queryLimitVoList.forEach(item ->{
                switch (item.getQueryLimitMonths()){
                    case 1 -> predicateMap.put(it -> item.getQueryLimitMaxCount() > 3,-20);
                    case 2 -> predicateMap.put(it -> item.getQueryLimitMaxCount() > 5,-20);
                    case 3 -> predicateMap.put(it -> item.getQueryLimitMaxCount() > 7,-20);
                    case 6 -> predicateMap.put(it -> item.getQueryLimitMaxCount() > 9,-20);
                    case 12 -> predicateMap.put(it -> item.getQueryLimitMaxCount() > 15,-20);
                    case 24 -> predicateMap.put(it -> item.getQueryLimitMaxCount() > 30,-20);
                    default -> {}
                }
            });
        });
        /*
        当前最长逾期月数>0	-30
        近半年最长逾期月数>1	-30
        近一年最长逾期月数>2	-30
        近两年最长逾期月数>3	-30
        24个月最大连续逾期次数>2	-30
        24个月逾期次数>5	-30
         */
        if (StringUtils.isNotBlank(detailsDO.getCreditReportOverdueJson())) {
            Map<String, List<OverdueRecordVo>> mapOverdue = JSON.parseObject(detailsDO.getCreditReportOverdueJson(), new TypeReference<>() {});
            if (mapOverdue.containsKey(LOANS)) {
                List<OverdueRecordVo> overdueRecordVos = mapOverdue.get(LOANS);
                overdueCreditScore(overdueRecordVos,predicateMap);
            }
            if (mapOverdue.containsKey(CREDITCARD)) {
                List<OverdueRecordVo> overdueRecordVos = mapOverdue.get(CREDITCARD);
                overdueCreditScore(overdueRecordVos,predicateMap);

            }
        }
        /*
            学历
            硕士  +30
            本科  +25
            大专  +20
            高中及以下
         */
        Map<Predicate<CreditReportAdmittanceConditionSaveReqVO>,Integer> predicateConditionMap = new LinkedHashMap<>();
        predicateConditionMap.put(item ->Objects.nonNull(item.getEducation()) && Objects.equals(item.getEducation(),4),30);
        predicateConditionMap.put(item ->Objects.nonNull(item.getEducation()) && Objects.equals(item.getEducation(),3),25);
        predicateConditionMap.put(item ->Objects.nonNull(item.getEducation()) && Objects.equals(item.getEducation(),2),20);
        /*
            单位性质
            公务员 +35
            央企、国企、上市公司 +30
            普通单位 +25
         */
        predicateConditionMap.put(item ->StringUtils.isNotBlank(item.getUnitNature()) && Objects.equals(item.getUnitNature(),"1"),35);
        predicateConditionMap.put(item ->StringUtils.isNotBlank(item.getUnitNature()) && Objects.equals(item.getUnitNature(),"2"),30);
        predicateConditionMap.put(item ->StringUtils.isNotBlank(item.getUnitNature()) && Objects.equals(item.getUnitNature(),"3"),25);
        /*
            社保缴纳时长
         */
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportSocialMonths()) && Objects.equals(item.getCreditReportSocialMonths(),60),30);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportSocialMonths()) && Objects.equals(item.getCreditReportSocialMonths(),48),25);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportSocialMonths()) && Objects.equals(item.getCreditReportSocialMonths(),36),20);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportSocialMonths()) && Objects.equals(item.getCreditReportSocialMonths(),24),15);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportSocialMonths()) && Objects.equals(item.getCreditReportSocialMonths(),12),10);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportSocialMonths()) && Objects.equals(item.getCreditReportSocialMonths(),6),5);
        /*
            公积金缴纳时长
         */
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportFundMonths()) && Objects.equals(item.getCreditReportFundMonths(),60),35);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportFundMonths()) && Objects.equals(item.getCreditReportFundMonths(),48),30);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportFundMonths()) && Objects.equals(item.getCreditReportFundMonths(),36),25);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportFundMonths()) && Objects.equals(item.getCreditReportFundMonths(),24),20);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportFundMonths()) && Objects.equals(item.getCreditReportFundMonths(),12),15);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportFundMonths()) && Objects.equals(item.getCreditReportFundMonths(),6),10);
        /*
            社保缴纳基数
         */
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportSocialBase()) && item.getCreditReportSocialBase() > 10000,25);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportSocialBase()) && item.getCreditReportSocialBase() > 8000 && item.getCreditReportSocialBase() <= 10000,20);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportSocialBase()) && item.getCreditReportSocialBase() > 6000 && item.getCreditReportSocialBase() <= 8000,15);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportSocialBase()) && item.getCreditReportSocialBase() > 5000 && item.getCreditReportSocialBase() <= 6000,10);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportSocialBase()) && item.getCreditReportSocialBase() > 4000 && item.getCreditReportSocialBase() <= 5000,5);
        /*
            公积金缴纳基数
         */
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportFundBase()) && item.getCreditReportFundBase() > 10000,40);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportFundBase()) && item.getCreditReportFundBase() > 8000 && item.getCreditReportFundBase() <= 10000,35);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportFundBase()) && item.getCreditReportFundBase() > 7000 && item.getCreditReportFundBase() <= 8000,30);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportFundBase()) && item.getCreditReportFundBase() > 6000 && item.getCreditReportFundBase() <= 7000,20);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportFundBase()) && item.getCreditReportFundBase() > 5000 && item.getCreditReportFundBase() <= 6000,10);
        predicateConditionMap.put(item ->Objects.nonNull(item.getCreditReportFundBase()) && item.getCreditReportFundBase() > 4000 && item.getCreditReportFundBase() <= 5000,5);
        /*
            个税-年收入
         */
        predicateConditionMap.put(item ->Objects.nonNull(item.getAnnualIncome()) && isGreater(item.getAnnualIncome(),BigDecimal.valueOf(1000000)) ,60);
        predicateConditionMap.put(item ->Objects.nonNull(item.getAnnualIncome()) && isGreater(item.getAnnualIncome(),BigDecimal.valueOf(800000))
                && isLessOrEqual(item.getAnnualIncome(),BigDecimal.valueOf(1000000)),50);
        predicateConditionMap.put(item ->Objects.nonNull(item.getAnnualIncome()) && isGreater(item.getAnnualIncome(),BigDecimal.valueOf(500000))
                && isLessOrEqual(item.getAnnualIncome(),BigDecimal.valueOf(800000)),40);
        predicateConditionMap.put(item ->Objects.nonNull(item.getAnnualIncome()) && isGreater(item.getAnnualIncome(),BigDecimal.valueOf(300000))
                && isLessOrEqual(item.getAnnualIncome(),BigDecimal.valueOf(500000)),30);
        predicateConditionMap.put(item ->Objects.nonNull(item.getAnnualIncome()) && isGreater(item.getAnnualIncome(),BigDecimal.valueOf(200000))
                && isLessOrEqual(item.getAnnualIncome(),BigDecimal.valueOf(300000)),20);
        predicateConditionMap.put(item ->Objects.nonNull(item.getAnnualIncome()) && isGreater(item.getAnnualIncome(),BigDecimal.valueOf(100000))
                && isLessOrEqual(item.getAnnualIncome(),BigDecimal.valueOf(200000)),10);
        /*
            房
         */
        predicateConditionMap.put(item -> Objects.nonNull(item.getIsFullPayment()) && Objects.equals(item.getIsFullPayment(),1),30);
        predicateConditionMap.put(item -> Objects.nonNull(item.getIsMortgage()) && Objects.equals(item.getIsMortgage(),1),30);
        /*
            车
         */
        predicateConditionMap.put(item -> Objects.nonNull(item.getIsFullPaymentVehicle()) && Objects.equals(item.getIsFullPaymentVehicle(),1),30);
        predicateConditionMap.put(item -> Objects.nonNull(item.getIsMortgageVehicle()) && Objects.equals(item.getIsMortgageVehicle(),1),20);
        /*
           南京户籍
         */
        predicateConditionMap.put(item -> Objects.nonNull(item.getCensusRegister()) && Objects.equals(item.getCensusRegister(),"320100"),5);
        /*
            年龄30-50
         */
        predicateConditionMap.put(item -> Objects.nonNull(item.getAge()) && item.getAge() >= 30 && item.getAge() <= 50,5);

        /*
            计算总和
         */
        AtomicInteger basicSum = new AtomicInteger();
        predicateConditionMap.forEach((it,value) -> {
            if (it.test(conditionDO)) {
                log.info("基础信息判断 计算信用分-判断成功 value={}",value);

                basicSum.addAndGet(value);
            }
        });
        AtomicInteger overdueSum = new AtomicInteger(600);
        predicateMap.forEach((it,value) -> {
            if (it.test(detailsDO)) {
                log.info("征信信息-计算信用分-判断成功value={}",value);

                overdueSum.addAndGet(value);
            }
        });
        int creditScore =overdueSum.get()+ basicSum.get();

        /*
            更新信用分
         */
        CreditReportBasicDO creditReportBasic = creditReportBasicService.getCreditReportBasic(detailsDO.getCreditBasicId());
        if (Objects.equals(creditReportBasic.getMarriageStatus(),"已婚")){
            creditScore+=5;
        }
        LambdaUpdateWrapper<CreditReportDetailsDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Objects.nonNull(detailsDO.getCreditBasicId()),CreditReportDetailsDO::getCreditBasicId, detailsDO.getCreditBasicId());
        updateWrapper.eq(Objects.nonNull(detailsDO.getCreditBasicId()),CreditReportDetailsDO::getCreditBasicId, conditionDO.getCreditBasicId());
        updateWrapper.set(CreditReportDetailsDO::getCreditScore, creditScore);
        creditReportDetailsMapper.update(updateWrapper);
        detailsDO.setCreditScore(creditScore);
        return creditScore;
    }
    /**
     * 公共方法
     * 解析查询记录
     * 解析机构查询
     */
    public void analysisQueryRecord(String creditReportQueryJson, Consumer<List<QueryLimitVo>> consumer)  {
        if (StringUtils.isNotBlank(creditReportQueryJson)) {
            List<QueryLimitVo> mapRecord = JSON.parseObject(creditReportQueryJson, new TypeReference<>() {});
            if (mapRecord != null && !mapRecord.isEmpty()) {
                List<QueryLimitVo> list = mapRecord.stream().filter(item -> item.getQueryLimitWay() == 1).toList();
                if (!list.isEmpty()) {
                    consumer.accept(list);
                }
            }
        }else {
            consumer.accept(new ArrayList<>());
        }
    }

    /**
     * 拼接逾期情况
     * @param overdueRecordVos 逾期详情集合
     * @param predicateMap 条件表达式
     */
    private static void overdueCreditScore(List<OverdueRecordVo> overdueRecordVos, Map<Predicate<CreditReportDetailsSaveReqVO>,Integer> predicateMap) {
        overdueRecordVos.forEach(overdueRecordVo -> {
            String months = overdueRecordVo.getContinuousOverdueMonths().split(COMMA)[0];
            switch (months){
                case "1" -> predicateMap.put(item-> Integer.parseInt(overdueRecordVo.getMaxMonthsOverdueMonths().split(COMMA)[1]) > 0,-30);
                case "6" -> predicateMap.put(item-> Integer.parseInt(overdueRecordVo.getMaxMonthsOverdueMonths().split(COMMA)[1]) > 1,-30);
                case "12" -> predicateMap.put(item-> Integer.parseInt(overdueRecordVo.getMaxMonthsOverdueMonths().split(COMMA)[1]) > 2,-30);
                case "24" -> {
                    predicateMap.put(item-> Integer.parseInt(overdueRecordVo.getMaxMonthsOverdueMonths().split(COMMA)[1]) > 3,-30);
                    predicateMap.put(item-> Integer.parseInt(overdueRecordVo.getContinuousOverdueMonths().split(COMMA)[1]) > 2,-30);
                    predicateMap.put(item-> Integer.parseInt(overdueRecordVo.getOverUeRecordMonths().split(COMMA)[1]) > 5,-30);
                }
                default -> {}
            }
        });
    }

    /**
     * 比较两个BigDecimal val1 大于 val2
     * @param val1 值1
     * @param val2  值2
     * @return true/false
     */
    public static boolean isGreater(BigDecimal val1, BigDecimal val2) {
        return val1 != null && val2 != null && val1.compareTo(val2) > 0;
    }


    /**
     * 比较两个BigDecimal val1 小于等于 val2
     * @param val1 值1
     * @param val2  值2
     * @return true/false
     */
    public static boolean isLessOrEqual(BigDecimal val1, BigDecimal val2) {
        return val1 != null && val2 != null && val1.compareTo(val2) <= 0;
    }

    /**
     * 获取负债概要
     */
    @Override
    public void getBasicInfoDebt(Map<String, Object> parenMap,
                                 String parentName, CreditReportDetailsSaveReqVO detailsDO, Map<String, Integer> mechanismNumberMap) {
            String status = (String) parenMap.get(ACCOUNT_STATUS);
            // 贷款银行名称为管理机构
            String governingBody = (String)parenMap.get(GOVERNING_BODY);
            // 信用卡名称为发卡机构
            String cardIssuer = (String)parenMap.get(CARD_ISSUER);
             /*
                逾期信息明细
             */
            List<CreditReportLoanOverdueDO> creditReportLoanOverdueDOList = new ArrayList<>();
            Map<String,YearlyRecord> repaymentRecord = (Map<String,YearlyRecord>)parenMap.get(OVERDUE_REPAYMENT_RECORD);
            // 将单个账户所有还价记录按照时间顺序组成一个集合
            List<YearlyRecord> yearlyRecordList = getAnalysisJson(repaymentRecord,null,new AtomicBoolean(true));
            // 还款记录不为空开始计算
            if (!yearlyRecordList.isEmpty()) {
                List<Map<String, String>> analysisJson = jsonToList(yearlyRecordList);
                int sumLengthOfMonth = findSumLengthOfNumber(analysisJson, analysisJson.size());
                int maxLengthOfMonth = findMaxLengthOfMonth(analysisJson, analysisJson.size());
                BigDecimal maxLengthOfMoney = findMaxLengthOfMoney(analysisJson, analysisJson.size());
                if (sumLengthOfMonth > 0) {
                    // 信用卡/用户 key不一样
                    String balance = convertMoney((String)parenMap.get(LOAN_AMOUNT));
                    String yotalAmount = convertMoney((String)parenMap.get(ACCOUNT_CREDIT_LIMIT));
                    CreditReportLoanOverdueDO creditReportLoanOverdueDO = new CreditReportLoanOverdueDO();
                    creditReportLoanOverdueDO.setOrganizationName(Objects.isNull(governingBody) ? cardIssuer : governingBody);
                    creditReportLoanOverdueDO.setStatus(status);
                    creditReportLoanOverdueDO.setAmountOwed(new BigDecimal(Objects.equals(balance, "0") ? yotalAmount : balance));
                    creditReportLoanOverdueDO.setOverdueMoney(maxLengthOfMoney);
                    creditReportLoanOverdueDO.setOverdueMonth(maxLengthOfMonth);
                    creditReportLoanOverdueDO.setOverdueNumber(sumLengthOfMonth);
                    creditReportLoanOverdueDOList.add(creditReportLoanOverdueDO);
                }
            }
            if (Objects.isNull(detailsDO.getLoanOverdueList()) || detailsDO.getLoanOverdueList().isEmpty()) {
                detailsDO.setLoanOverdueList(creditReportLoanOverdueDOList);
            } else {
                // 累加
                List<CreditReportLoanOverdueDO> loanOverdueList = detailsDO.getLoanOverdueList();
                loanOverdueList.addAll(creditReportLoanOverdueDOList);
                detailsDO.setLoanOverdueList(loanOverdueList);
            }

            // 判断是否为正常  true 未已结清或者销户
            if (isAccountStatus(status)) {
                return;
            }
            /*
               业务概要解析
             */
            String business = (String)parenMap.get(BUSINESS_TYPE);
            // 获取担保方式
            String styleGuaranty = (String)parenMap.get(GUARANTY_STYLE);
            // 五级分类
            String fiveClassClassification = (String)parenMap.get(THE_FIVE_CLASS_CLASSIFICATION);
            /*
                取值：信贷交易信息明细-账户，账户状态为非“未结清”，业务种类：个人住房贷款、个人商用房贷款（包括商住两用房），账户数：所有账户数相➕；总余额：所有余额相
             */
            if ((business.contains(PERSONAL_HOUSING_LOAN) || business.contains(PERSONAL_COMMERCIAL_PROPERTY_LOAN))) {
                // 住房按揭
                accumulate(detailsDO, null, parenMap,
                        Integer::parseInt, CreditReportDetailsSaveReqVO::setHousingMortgageAccount,
                        CreditReportDetailsSaveReqVO::getHousingMortgageAccount, 1);
                accumulate(detailsDO, BALANCE, parenMap,
                        BigDecimal::new, CreditReportDetailsSaveReqVO::setHousingMortgageMoney,
                        CreditReportDetailsSaveReqVO::getHousingMortgageMoney, null);
            }
            /*
            取值：信贷交易信息明细-账户，账户状态为 “未结清”，业务种类：个人汽车消费贷款，账户数：所有账户数相➕；总余额：所有余额相
             */
            else if (Objects.equals(business, PERSONAL_AUTO_LOAN)) {
                // 车辆按揭
                accumulate(detailsDO, null, parenMap,
                        Integer::parseInt, CreditReportDetailsSaveReqVO::setVehicleAccount,
                        CreditReportDetailsSaveReqVO::getVehicleAccount, 1);
                accumulate(detailsDO, BALANCE, parenMap,
                        BigDecimal::new, CreditReportDetailsSaveReqVO::setVehicleMoney,
                        CreditReportDetailsSaveReqVO::getVehicleMoney, null);
            }
            /*
            取值：信贷交易信息明细-（非循环贷账户、循环贷账户一、循环贷账户二）所有管理机构：账户状态为为 “未结清”，名称判断有【银行】汉字，机构数：所有机构数相➕；总余额：所有余额相➕
             */
            if (!parentName.contains(CREDIT_CARD_ACCOUNT_NAME) ) {
                List<CreditReportLoanDetailsDO> loanDetailsDOList = detailsDO.getLoanOverdueDetailsList();
                /*
                    贷款机构：可编辑；取值：信贷交易信息明细-（非循环贷账户、循环贷账户一、循环贷账户二）所有管理机构：账户状态为未结清的机构名称列表展示
                    业务种类：可编辑；取值：对应前面机构名称，取明细中业务种类
                    担保方式：可编辑；取值：对应前面机构名称，取明细中担保方式
                    账户状态：可编辑；取值：对应前面机构名称，取明细中账户状态
                    五级分类：可编辑；取值：对应前面机构名称，取明细中五级分类
                    借款金额：可编辑；取值：对应前面机构名称，取明细中借款金额
                    余额：可编辑；取值：对应前面机构名称，取明细中余额
                 */
                // 获取 银行贷款机构明细
                CreditReportLoanDetailsDO loanDetailsDO = CreditReportLoanDetailsDO.builder()
                        .lendingInstitutionName(governingBody)
                        .businessTypes(BUSINESS_TYPE)
                        .guaranteeMethod(GUARANTY_STYLE)
                        .accountStatus(status)
                        .fiveLevel(fiveClassClassification)
                        .loanAmount(convertMoney((String)parenMap.get(LOAN_AMOUNT)))
                        .balance(convertMoney((String)parenMap.get(BALANCE)))
                        .build();
                loanDetailsDOList.add(loanDetailsDO);

                // 贷款的管理不机构不为空并且存在银行字符  则为银行按揭 否则为非银行按揭
                if (Objects.nonNull(governingBody) && governingBody.contains(BANK)) {
                    // 银行按揭
                    accumulate(detailsDO, null, parenMap,
                            Integer::parseInt, CreditReportDetailsSaveReqVO::setBankingOrganizationAccount,
                            CreditReportDetailsSaveReqVO::getBankingOrganizationAccount, 1);
                    accumulate(detailsDO, BALANCE, parenMap,
                            BigDecimal::new, CreditReportDetailsSaveReqVO::setBankingOrganizationMoney,
                            CreditReportDetailsSaveReqVO::getBankingOrganizationMoney, null);
                }
                /*
                取值：信贷交易信息明细-（非循环贷账户、循环贷账户一、循环贷账户二）所有管理机构：账户状态为为 “未结清”，名称判断无【银行】汉字，机构数：所有机构数相➕；总余额：所有余额相
                 */
                else {
                    // 非银行按揭
                    accumulate(detailsDO, null, parenMap,
                            Integer::parseInt, CreditReportDetailsSaveReqVO::setNonBankingOrganizationAccount,
                            CreditReportDetailsSaveReqVO::getNonBankingOrganizationAccount, 1);
                    accumulate(detailsDO, BALANCE, parenMap,
                            BigDecimal::new, CreditReportDetailsSaveReqVO::setNonBankingOrganizationMoney,
                            CreditReportDetailsSaveReqVO::getNonBankingOrganizationMoney, null);
                }
            }else {
                /*
                    发卡机构：可编辑；取值：贷记卡账户-（贷记卡、准贷记卡）所有发卡机构下，账户状态为未结清的发卡机构名称列表展示
                    账户状态：可编辑；取值：对应前面机构名称，取明细中账户状态
                    授信额度：可编辑；取值：对应前面发卡机构名称，取明细中授信额度
                    已用额度：可编辑；取值：对应前面发卡机构名称，取明细中已用额度
                    余额：可编辑；取值：对应前面发卡机构名称，取明细中余额
                 */
                // 获取 信用卡明细
                List<CreditReportCreditCardDetailsDO> creditCardDetailsDOList = detailsDO.getLoanOverdueCreditCardDetailsList();
                CreditReportCreditCardDetailsDO reportCreditCardDetailsDO = CreditReportCreditCardDetailsDO.builder()
                        .hairpinInstitutionName(cardIssuer)
                        .accountStatus(status)
                        .creditLine(convertMoney((String)parenMap.get(TOTAL_CREDIT_LINE)))
                        .usedQuota(convertMoney((String)parenMap.get(USED_CREDIT)))
                        .balance(convertMoney((String)parenMap.get(BALANCE)))
                        .build();
                creditCardDetailsDOList.add(reportCreditCardDetailsDO);
            }
            /*
            取值：信贷交易信息明细-（非循环贷账户、循环贷账户一、循环贷账户二）所有管理机构：账户状态：未结清 担保方式为：信用/无担保、保证，的所有机构数，机构数需要去重
            取值：信贷交易信息明细-（非循环贷账户、循环贷账户一、循环贷账户二）所有管理机构：账户状态：未结清 担保方式为：信用/无担保、保证，的所有机构数，机构数下的所有余额总和
              信用贷款 信息
              1.    计算 信用贷款 账户状态未结清 && 非信用卡 && 担保方式为 信用/无担保
              2.    计算五级分类 账户状态未结清 && 非信用卡
             */
            //账户状态未结清 && 非信用卡
            if (!parentName.contains(CREDIT_CARD_ACCOUNT_NAME)) {
                // 计算 信用贷款  担保方式为 信用/无担保
                if (Objects.equals(styleGuaranty, CREDIT_NO_GUARANTEE)) {
                    // 信用贷款机构不重复
                    if (!mechanismNumberMap.containsKey("details" + governingBody)) {
                        mechanismNumberMap.put("details" + governingBody, 1);
                        // 信用贷款
                        accumulate(detailsDO, null, parenMap,
                                Integer::parseInt, CreditReportDetailsSaveReqVO::setCreditLoanOrgCount,
                                CreditReportDetailsSaveReqVO::getCreditLoanOrgCount, 1);
                    }
                    // 余额计算重复的机构余额
                    accumulate(detailsDO, BALANCE, parenMap,
                            BigDecimal::new, CreditReportDetailsSaveReqVO::setCreditLoanMoneyCount,
                            CreditReportDetailsSaveReqVO::getCreditLoanMoneyCount, null);

                }
                /*
                取值：正常：信贷交易信息明细-（非循环贷账户、循环贷账户一、循环贷账户二）“五级分类“为非正常的数量=0；非正常：非正常的数量>0
                备注：   1）五级分类的状态有：正常，关注，次级，可疑，损失，只要五级分类有(关注，次级，可疑，损失)为非正常
                        2）账户状态为结清时，不显示五级分类情况
                        3）只有贷款账户才会有五级分类，信用卡（贷记卡/准贷记卡）不存在五级分类
                 */
                // 五级分类 非正常加1
                if (!Objects.equals(fiveClassClassification, NORMAL) && Objects.isNull(detailsDO.getCreditReportFiveLevel())) {
                    accumulate(detailsDO, null, parenMap,
                            Integer::parseInt, CreditReportDetailsSaveReqVO::setCreditReportFiveLevel,
                            CreditReportDetailsSaveReqVO::getCreditReportFiveLevel, 1);
                }

            }

    }


    public void getTotalLiabilities(CreditReportDetailsSaveReqVO detailsDO) {
        //负债总数 = 信用卡已用额度+贷款余额 + 担保余额 totalLiabilities
        BigDecimal creditCardUsedCredit = BigDecimal.ZERO;
        if (Objects.nonNull(detailsDO.getCreditCardUsedCredit())) {
            creditCardUsedCredit = detailsDO.getCreditCardUsedCredit();
        }
        detailsDO.setCreditCardBalance(creditCardUsedCredit);
        BigDecimal debtNonCyclicalBalance = BigDecimal.ZERO;
        if (Objects.nonNull(detailsDO.getDebtNonCyclicalBalance())) {
            debtNonCyclicalBalance = detailsDO.getDebtNonCyclicalBalance();
        }
        BigDecimal debtOneCyclicalBalance = BigDecimal.ZERO;
        if (Objects.nonNull(detailsDO.getDebtOneCyclicalBalance())) {
            debtOneCyclicalBalance = detailsDO.getDebtOneCyclicalBalance();
        }
        BigDecimal debtTowCyclicalBalance = BigDecimal.ZERO;
        if (Objects.nonNull(detailsDO.getDebtTowCyclicalBalance())) {
            debtTowCyclicalBalance = detailsDO.getDebtTowCyclicalBalance();
        }

        detailsDO.setTotalLiabilities(creditCardUsedCredit.add(debtNonCyclicalBalance).add(debtOneCyclicalBalance).add(debtTowCyclicalBalance));

        // 贷款余额等于非循环贷账户余额+循环贷账户余额
        detailsDO.setDebtCyclicalGrossAmount(debtNonCyclicalBalance.add(debtOneCyclicalBalance).add(debtTowCyclicalBalance));
        // 信用卡余额等于贷记卡、准贷记卡账户信息已用额度汇总
        // 担保余额等于相关还款责任信息汇总-余额（个人、企业都统计，如果两个都有，余额相➕总和）
    }


    @Override
    public Map<String, List<OverdueRecordVo>> calculateOverdue(CreditReportDetailsSaveReqVO updateReqVO) {
        Map<String, List<OverdueRecordVo>> overdueSummaryMap = JSON.parseObject(updateReqVO.getCreditReportOverdueJson(), new TypeReference<>() {});
        List<OverdueRecordVo> overdueSummary = overdueSummaryMap.values()
                .stream()
                .flatMap(List::stream)
                .toList();
       /*
        逾期汇总计算
                */
        Map<String, Integer> overdue = new LinkedHashMap<>();
        overdueSummary.forEach(item -> {
            // 直接调用辅助方法处理每一个可能的逾期字段
            processOverdueField(item.getContinuousOverdueMonths(), "continuousOverdueMonths", overdue, COMMA,"2");
            processOverdueField(item.getMaxMonthsOverdueMonths(), "maxMonthsOverdueMonths", overdue, COMMA,"2");
            processOverdueField(item.getOverUeRecordMonths(), "overUeRecordMonths", overdue, COMMA,"1");
            processOverdueField(item.getMaxMonthsOverdueAmountMonths(), "maxMonthsOverdueAmountMonths", overdue, COMMA,"2");
        });
        // 如果聚合后的 map 不为空，则按类别过滤并处理数据
        if (!overdue.isEmpty()) {
            List<OverdueRecordVo> overdueRecordVos =  getOverdueRecordVos(overdue);
            overdueSummaryMap.put("summary",overdueRecordVos);
        }
        return overdueSummaryMap;
    }
}